package com.jason.measure.view;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;

/**
 * @Author: Jason
 * @Date: 2016/11/1
 * @Time: 10:47.
 */

public class SquareLayout6 extends ViewGroup {

    private static final String TAG = SquareLayout6.class.getSimpleName();

    private static final int ORIENTATION_HORIZONTAL = 0, ORIENTATION_VERTICAL = 1; // 排列方向的常量
    private static final int DEFAULT_MAX_ROW = Integer.MAX_VALUE, DEFAULT_MAX_COLUMN = Integer.MAX_VALUE; // 最大行列默认值

    private int mMaxRow = DEFAULT_MAX_ROW; // 最大行数
    private int mMaxColumn = DEFAULT_MAX_COLUMN; // 最大列数

    private int mOrientation = ORIENTATION_HORIZONTAL; // 排列方向默认横向


    public SquareLayout6(Context context, AttributeSet attrs) {
        super(context, attrs);
        mMaxRow = mMaxColumn = 2;
    }


    /**
     * 让子元素的margins外边距能够被正确的计算,必须重写三个方法
     */
    @Override
    protected LayoutParams generateDefaultLayoutParams() {
        Log.e(TAG, "---generateDefaultLayoutParams---");
        return new MarginLayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
    }

    @Override
    protected LayoutParams generateLayoutParams(LayoutParams p) {
        Log.e(TAG, "---generateLayoutParams--p---");
        return new MarginLayoutParams(p);
    }

    @Override
    public LayoutParams generateLayoutParams(AttributeSet attrs) {
        Log.e(TAG, "---checkLayoutParams---attrs---");
        return new MarginLayoutParams(getContext(), attrs);
    }

    // 重写 checkLayoutParams验证当前LayoutParams对象是否为MarginLayoutParams的实例
    @Override
    protected boolean checkLayoutParams(LayoutParams p) {
        Log.e(TAG, "---checkLayoutParams---");
        return p instanceof MarginLayoutParams;
    }


    // 测量控件  有5个子元素  暂定最大列为2
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        Log.e(TAG, "---onMeasure---");

        // 声明临时变量存储父容器的期望值  该值应该对于父容器的内边距加上所有子元素的测量宽高和外边距
        int parentDesireWidth = 0;
        int parentDesireHeight = 0;

        // 声明临时变量存储元素的测量状态
        int childMeasureState = 0;

        if (getChildCount() > 0) {
            // 声明两个一维数组存储子元素宽高数据
            int[] childWidths = new int[getChildCount()];
            int[] childHeights = new int[getChildCount()];

            for (int i = 0; i < getChildCount(); i++) {
                View child = getChildAt(i);
                // 如果该子元素没有以"不占用空间"的方式隐藏则表示其需要被测量计算
                if (child.getVisibility() != View.GONE) {
                    // 测量子元素 并考量其外边距
                    measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);

                    // 比较子元素测量宽高 并比较取其较大值
                    int childMeasureSize = Math.max(child.getMeasuredWidth(), child.getMeasuredHeight());

                    // 重新封装子元素的测量规格
                    int childMeasureSpce = MeasureSpec.makeMeasureSpec(childMeasureSize, MeasureSpec.EXACTLY);

                    // 重新测量子元素
                    child.measure(childMeasureSpce, childMeasureSpce);

                    // 获取子元素布局参数
                    MarginLayoutParams mlp = (MarginLayoutParams) child.getLayoutParams();

                    // 考量外边距计算子元素实际宽高并将数据存入数组
                    childWidths[i] = child.getMeasuredWidth() + mlp.leftMargin + mlp.rightMargin;
                    childHeights[i] = child.getMeasuredHeight() + mlp.topMargin + mlp.bottomMargin;

                    // 合并子元素的测量状态
                    childMeasureState = combineMeasuredStates(childMeasureState, child.getMeasuredState());

                }
            }

            // 声明临时变量存储 行/列宽高
            int indexMultiWidth = 0, indexMultiHeight = 0;

            // 如果为横向排列
            if (mOrientation == ORIENTATION_HORIZONTAL) {
                // 如果子元素数量大于限定则进行折行计算
                if (getChildCount() > mMaxColumn) {
                    // 计算产生的行数
                    int row = getChildCount() / mMaxColumn;
                    // 计算余数
                    int remainder = getChildCount() % mMaxColumn;

                    // 声明临时变量存储元素宽高数组下标值
                    int index = 0;

                    // 遍历数组计算父容器期望宽高值
                    for (int x = 0; x < row; x++) {

                        for (int y = 0; y < mMaxColumn; y++) {
                            // 单行宽度累加
                            indexMultiWidth += childWidths[index];

                            // 单行高度取最大值
                            indexMultiHeight = Math.max(indexMultiHeight, childWidths[index++]);

                        }

                        // 每一行遍历完后将该行宽度与上一行宽度比较取最大值
                        parentDesireWidth = Math.max(parentDesireWidth, indexMultiWidth);

                        // 每一行遍历完后累加各行高度
                        parentDesireHeight += indexMultiHeight;

                        // 重置参数
                        indexMultiWidth = indexMultiHeight = 0;
                    }

                    // 如果有余数表示有子元素未能占据一行
                    if (remainder != 0) {
                        // 遍历剩下的这些子元素 将其宽高计算到父容器期望值
                        for (int i = getChildCount() - remainder; i < getChildCount(); i++) {
                            indexMultiWidth += childWidths[i];
                            indexMultiHeight = Math.max(indexMultiHeight, childHeights[i]);
                        }

                        parentDesireWidth = Math.max(parentDesireWidth, indexMultiWidth);
                        parentDesireHeight += indexMultiHeight;
                        indexMultiWidth = indexMultiHeight = 0;
                    }

                } else {  // 如果子元素数量还没有限制值大 那么直接计算即可 无需折行

                    for (int i = 0; i < getChildCount(); i++) {
                        // 累计子元素的实际高度
                        parentDesireHeight += childHeights[i];

                        // 获取子元素中宽度最大值
                        parentDesireWidth = Math.max(parentDesireWidth, childWidths[i]);
                    }

                }

            } else if (mOrientation == ORIENTATION_VERTICAL) { // 如果为竖向排列

                if (getChildCount() > mMaxRow) {
                    int column = getChildCount() / mMaxRow;
                    int remainder = getChildCount() % mMaxRow;
                    int index = 0;

                    for (int x = 0; x < column; x++) {
                        for (int y = 0; y < mMaxRow; y++) {
                            indexMultiHeight += childHeights[index];
                            indexMultiWidth = Math.max(indexMultiWidth, childWidths[index++]);
                        }

                        parentDesireHeight = Math.max(parentDesireHeight, indexMultiHeight);
                        parentDesireWidth += indexMultiWidth;
                        indexMultiWidth = indexMultiHeight = 0;
                    }

                    if (remainder != 0) {
                        for (int i = getChildCount() - remainder; i < getChildCount(); i++) {
                            indexMultiHeight += childHeights[i];
                            indexMultiWidth = Math.max(indexMultiHeight, childWidths[i]);
                        }
                        parentDesireHeight = Math.max(parentDesireHeight, indexMultiHeight);
                        parentDesireWidth += indexMultiWidth;
                        indexMultiWidth = indexMultiHeight = 0;
                    }


                } else {

                    for (int i = 0; i < getChildCount(); i++) {
                        // 累加子元素的实际宽度
                        parentDesireHeight += childWidths[i];
                        // 获取子元素中高度最大值
                        parentDesireHeight = Math.max(parentDesireHeight, childHeights[i]);
                    }

                }

            }

            // 考量父容器内边距将其累加到期望值
            parentDesireWidth += getPaddingLeft() + getPaddingRight();
            parentDesireHeight += getPaddingTop() + getPaddingBottom();

            // 尝试比较父容器期望值与Android建议的最小值大小并取较大值
            parentDesireWidth = Math.max(parentDesireWidth, getSuggestedMinimumWidth());
            parentDesireHeight = Math.max(parentDesireHeight, getSuggestedMinimumHeight());
        }

        // 确定父容器的测量宽高
        setMeasuredDimension(resolveSizeAndState(parentDesireWidth, widthMeasureSpec, childMeasureState),
                resolveSizeAndState(parentDesireHeight, heightMeasureSpec, childMeasureState << MEASURED_HEIGHT_STATE_SHIFT));


    }


    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {

        Log.e(TAG, "---onLayout---");

        // 如果父容器有子元素
        if (getChildCount() > 0) {
            // 声明临时变量存储宽高倍增值
            int multi = 0;
            // 指数倍增值
            int indexMulti = 1;

            // 存储列行/列宽高
            int indexMultiWidth = 0, indexMultiHeight = 0;

            // 临时变量存储行/列临时宽高
            int tempHeight = 0, tempWidth = 0;

            for (int i = 0; i < getChildCount(); i++) {
                View child = getChildAt(i);

                // 计算出算空间的view
                if (child.getVisibility() != View.GONE) {
                    // 获取子元素的布局参数
                    MarginLayoutParams mlp = (MarginLayoutParams) child.getLayoutParams();

                    // 获取控件尺寸
                    int childActualSize = child.getMeasuredWidth();

                    // 如果未横向排列
                    if (mOrientation == ORIENTATION_HORIZONTAL) {
                        // 子元素数量比限定值大
                        if (getChildCount() > mMaxColumn) {
                            // 根据当前子元素进行布局

                            if (i < mMaxColumn * indexMulti) {
                                child.layout(getPaddingLeft() + mlp.leftMargin + indexMultiWidth,
                                        getPaddingTop() + mlp.topMargin + indexMultiHeight,
                                        childActualSize + getPaddingLeft() + mlp.leftMargin + indexMultiWidth,
                                        childActualSize + getPaddingTop() + mlp.topMargin + indexMultiHeight);

                                indexMultiWidth += childActualSize + mlp.leftMargin + mlp.rightMargin;
                                tempHeight = Math.max(tempHeight, childActualSize) + mlp.topMargin + mlp.bottomMargin;

                                // 如果下一次遍历到的子元素下标值大于限定值
                                if (i + 1 >= mMaxColumn * indexMulti) {
                                    // 那么累加高度到高度倍增值
                                    indexMultiHeight += tempHeight;

                                    // 重置宽度倍增值
                                    indexMultiWidth = 0;

                                    // 增加指数倍增值
                                    indexMulti++;
                                }

                            } else {
                                // 确定子元素左上、右下坐标
                                child.layout(getPaddingLeft() + mlp.leftMargin + multi,
                                        getPaddingTop() + mlp.topMargin,
                                        childActualSize + getPaddingLeft() + mlp.leftMargin + multi,
                                        childActualSize + getPaddingTop() + mlp.topMargin);

                                // 累加倍增值
                                multi += childActualSize + mlp.leftMargin + mlp.rightMargin;

                            }
                        }


                    } else if (mOrientation == ORIENTATION_VERTICAL) { // 竖向排列

                        if (getChildCount() > mMaxRow) {
                            if (i < mMaxRow * indexMulti) {
                                child.layout(getPaddingLeft() + mlp.leftMargin + indexMultiWidth,
                                        getPaddingTop() + mlp.topMargin + indexMultiHeight,
                                        childActualSize + getPaddingLeft() + mlp.leftMargin + indexMultiWidth,
                                        childActualSize + getPaddingTop() + mlp.topMargin + indexMultiHeight);
                                indexMultiHeight += childActualSize + mlp.topMargin + mlp.bottomMargin;
                                tempWidth = Math.max(tempWidth, childActualSize) + mlp.leftMargin + mlp.rightMargin;
                                if (i + 1 >= mMaxRow * indexMulti) {
                                    indexMultiWidth += tempWidth;
                                    indexMultiHeight = 0;
                                    indexMulti++;
                                }
                            }

                        } else {
                            // 确定子元素左上右下坐标
                            child.layout(getPaddingLeft() + mlp.leftMargin,
                                    getPaddingTop() + mlp.topMargin + multi,
                                    childActualSize + getPaddingLeft() + mlp.leftMargin,
                                    childActualSize + getPaddingTop() + mlp.topMargin + multi);

                            // 累计倍增值
                            multi += childActualSize + mlp.topMargin + mlp.bottomMargin;
                        }

                    }


                }

            }


        }


    }
}







